/*
 * Copyright (c) 2025 Li Auto Inc. and its affiliates
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SRC_CPP_RTPS_TRANSPORT_UDSDGRAMCHANNELRESOURCE_H_
#define SRC_CPP_RTPS_TRANSPORT_UDSDGRAMCHANNELRESOURCE_H_

#include <queue>

#include <asio.hpp>
#include <ertps/utils/LocatorAlias.h>
#include <transport/ChannelResource.h>

namespace vbs {
namespace transport {

class ReceiverResource;
class UDSDgramTransportInterface;

typedef asio::local::datagram_protocol::socket udsDgramSocket;
typedef udsDgramSocket& udsDgramSocketRef;

inline udsDgramSocket* getSocketPtr(udsDgramSocket& socket) {
    return &socket;
}

inline const udsDgramSocket* getSocketPtr(const udsDgramSocket& socket) {
    return &socket;
}

inline udsDgramSocket createUDPSocket(asio::io_context& io_context) {
    return udsDgramSocket(io_context);
}

inline udsDgramSocket& getRefFromPtr(udsDgramSocket* socket) {
    return *socket;
}

class UDSDgramChannelResource : public ChannelResource {
 public:
    UDSDgramChannelResource(UDSDgramTransportInterface* transport, asio::local::datagram_protocol::socket& socket,
                            uint32_t maxMsgSize, const vbsutil::xmlparser::Locator_t& locator,
                            std::shared_ptr<ReceiverResource> receiver);

    ~UDSDgramChannelResource() override;

    UDSDgramChannelResource& operator=(UDSDgramChannelResource&& channelResource) {
        socket_ = std::move(channelResource.socket_);
        return *this;
    }

    inline udsDgramSocket* socket() { return getSocketPtr(socket_); }

    inline ReceiverResource* message_receiver() { return message_receiver_.get(); }

    inline void clear_message_receiver() { message_receiver_.reset(); }

    inline void disable() override { ChannelResource::disable(); }

    void release();

 protected:
    void perform_listen_operation(vbsutil::xmlparser::Locator_t input_locator, const std::string& thread_name);

    bool Receive(unsigned char* receive_buffer, uint32_t receive_buffer_capacity, uint32_t& receive_buffer_size,
                 asio::local::datagram_protocol::endpoint& remote_endpoint);

 private:
    std::shared_ptr<ReceiverResource> message_receiver_;
    asio::local::datagram_protocol::socket socket_;
    UDSDgramTransportInterface* transport_;
    UDSDgramChannelResource(const UDSDgramChannelResource&) = delete;
    UDSDgramChannelResource& operator=(const UDSDgramChannelResource) = delete;
};

}  // namespace transport
}  // namespace vbs

#endif
